/*
 *	OpenSource code or fragments by agile webentwicklung, Marcus Fuhrmeister
 *
 *	Redistribution and use in source and binary forms, with or without
 *	modification, are permitted provided that the following conditions
 *	are met:
 *  
 *		* Redistribution of source code must retain the above OpenSource comment,
 *		this list of conditions and the following disclaimer.
 * 
 *		* Redistribution in binary form must reproduce the above OpenSource comment,
 *		this list of conditions and the following disclaimer in the
 *		documentation and/or other materials provided with the distribution.
 * 
 *	Neither the name of 'avocaod systems, Marcus Fuhrmeister' or the
 *	names of contributors may be used to endorse or promote products derived
 *	from this software without specific prior written permission.
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
 */

package de.fuhrmeister.util;

import java.io.File;

import javax.swing.JFileChooser;
import javax.swing.JPanel;
import javax.swing.filechooser.FileFilter;

/**
 * Wrapper class to provide a system-pending <code>JFileChooser</code> dialog
 * for multi-file choosing.
 * 
 * @date	24.08.2010
 * @author	Marcus Fuhrmeister
 */
public class FileChooser extends JPanel {

	private static final long serialVersionUID = 291722732367453745L;
	private final JFileChooser fileChooser;
	private String fileName;
	private String[] fileNames;
	private String directory;
	private String completePath;
	private String[] completePaths;

	/**
	 * Constructor creates a new <code>JFileChooser</code> instance for files and
	 * directories.
	 * 
	 */
	public FileChooser() {
		this.fileChooser = new JFileChooser("./");
		this.fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
		this.fileChooser.setMultiSelectionEnabled(false);
		this.fileChooser.setDialogTitle("choose file");
	}

	/**
	 * Constructor creates a new <code>JFileChooser</code> instance with multi-choice for
	 * files.
	 * 
	 * @param boolean multi - true: multi-choice, false: single-choice
	 */
	public FileChooser(final boolean multi) {
		this.fileChooser = new JFileChooser("./");
		this.fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
		this.fileChooser.setMultiSelectionEnabled(multi);
		this.fileChooser.setDialogTitle("choose file");
	}

	/**
	 * Returns the complete path.
	 * 
	 * @return the complete path
	 */
	public String getCompletePath() {
		return this.completePath;
	}

	/**
	 * Sets the complete path.
	 * 
	 * @param completePath the complete path
	 */
	public void setCompletePath(final String completePath) {
		this.completePath = completePath;
	}

	/**
	 * Returns all the complete paths.
	 * 
	 * @return all the complete paths
	 */
	public String[] getCompletePaths() {
		return completePaths;
	}

	/**
	 * Sets all the complete paths.
	 * 
	 * @param completePaths all the complete paths
	 */
	public void setCompletePaths(final String[] completePaths) {
		this.completePaths = completePaths;
	}

	/**
	 * Returns the directory.
	 * 
	 * @return the directory
	 */
	public String getDirectory() {
		return this.directory;
	}

	/**
	 * Sets the directory.
	 * 
	 * @param directory the directory
	 */
	public void setDirectory(final String directory) {
		this.directory = directory;
	}

	/**
	 * Returns the file name.
	 * 
	 * @return the file name
	 */
	public String getFileName() {
		return fileName;
	}

	/**
	 * Sets the file name.
	 * 
	 * @param fileName the file name
	 */
	public void setFileName(final String fileName) {
		this.fileName = fileName;
	}

	/**
	 * Returns all the file names.
	 * 
	 * @return all the file names
	 */
	public String[] getFileNames() {
		return this.fileNames;
	}

	/**
	 * Sets all the file names.
	 * 
	 * @param fileNames the all file names
	 */
	public void setFileNames(final String[] fileNames) {
		this.fileNames = fileNames;
	}

	/**
	 * Calls to set a file filter.
	 * 
	 * @param fileFilterExt the file filter name
	 */
	public void setFileFilter(final String fileFilterExt) {
		this.fileChooser.setFileFilter(new FileChooser.Filter(fileFilterExt));
	}

	/**
	 * Calls to set a file filter and a description.
	 * 
	 * @param fileFilterExt the file filter name
	 * @param fileFilterDescription the file filter description
	 */
	public void setFileFilter(final String fileFilterExt, final String fileFilterDescription) {
		this.fileChooser.setFileFilter(new FileChooser.Filter(fileFilterExt, fileFilterDescription));
	}

	/**
	 * Calls to set the file filters.
	 * 
	 * @param fileFilterExt the file filter names
	 */
	public void setFileFilter(final String[] fileFilterExt) {
		this.fileChooser.setFileFilter(new FileChooser.Filter(fileFilterExt));
	}

	/**
	 * Calls to set a the file filters and a description.
	 * 
	 * @param fileFilterExt the file filter name
	 * @param fileFilterDescription the file filter description
	 */
	public void setFileFilter(final String[] fileFilterExt, final String fileFilterDescription) {
		this.fileChooser.setFileFilter(new FileChooser.Filter(fileFilterExt, fileFilterDescription));
	}

	/**
	 * Creates the dialog and saves the file properties.
	 * 
	 * TODO : this dialog is implemented only for files. It accepts multi and
	 * single selection. The code for directories has to be implemented.
	 */
	public boolean showOpenDialog(final java.awt.Component parent) {
		final int state = this.fileChooser.showOpenDialog(parent);
		// if the OK button was pressed
		if (state == JFileChooser.APPROVE_OPTION) {
			if (!this.fileChooser.isMultiSelectionEnabled()) {
				final File dest = this.fileChooser.getCurrentDirectory();
				this.directory = dest.getPath();
				final File file = this.fileChooser.getSelectedFile();
				this.fileName = file.getName();
				this.completePath = file.getPath();
				if (this.fileName == null) {
					return false;
				}
			}
			if (this.fileChooser.isMultiSelectionEnabled()) {
				final File dest = this.fileChooser.getCurrentDirectory();
				this.directory = dest.getPath();
				final File[] file = this.fileChooser.getSelectedFiles();
				this.fileNames = new String[file.length];
				this.completePaths = new String[file.length];
				for (int i = 0; i < file.length; i++) {
					this.fileNames[i] = file[i].getName();
					this.completePaths[i] = file[i].getPath();
					if (this.fileNames[i] == null) {
						return false;
					}
				}
			}
			return true;
		}
		// if the CANCEL button was pressed
		else {
			return false;
		}
	}

	/**
	 * Creates the dialog and saves the file properties.
	 * 
	 * TODO : this dialog is implemented only for files. It accepts multi and
	 * single selection. The code for directories has to be implemented.
	 */
	public void showSaveDialog(final javax.swing.JComponent parent) {
		final int state = this.fileChooser.showSaveDialog(parent);
		// if the OK button was pressed
		if (state == JFileChooser.APPROVE_OPTION) {
			if (!this.fileChooser.isMultiSelectionEnabled()) {
				final File dest = this.fileChooser.getCurrentDirectory();
				this.directory = dest.getPath();
				final File file = this.fileChooser.getSelectedFile();
				this.fileName = file.getName();
				this.completePath = file.getPath();
			}
			if (this.fileChooser.isMultiSelectionEnabled()) {
				final File dest = this.fileChooser.getCurrentDirectory();
				this.directory = dest.getPath();
				final File[] file = this.fileChooser.getSelectedFiles();
				this.fileNames = new String[file.length];
				this.completePaths = new String[file.length];
				for (int i = 0; i < file.length; i++) {
					this.fileNames[i] = file[i].getName();
					this.completePaths[i] = file[i].getPath();
				}
			}
		}
		// if the CANCEL button was pressed
		else {
			System.out.println("Selection canceled");
		}
	}

	/**
	 * Extends the <code>FileFilter</code> for multi-filter and description handling.
	 * 
	 *	@date		16.02.2012
	 *	@author		Marcus Fuhrmeister
	 */
	private class Filter extends FileFilter {

		private final String[] filter;
		private String description;

		/**
		 * Initializes the file filter with the default file extension.
		 */
		@SuppressWarnings("unused")
		public Filter() {
			this(".txt");
		}

		/**
		 * Constructor to set the given file filter.
		 * 
		 * @param filter the file filter
		 */
		public Filter(final String filter) {
			this.filter = new String[] { filter };
		}

		/**
		 * Constructor to set the given file filter and a description.
		 * 
		 * @param filter the file filter
		 * @param desc the file filter description
		 */
		public Filter(final String filter, final String desc) {
			this.filter = new String[] { filter };
			this.description = desc;
		}

		/**
		 * Constructor to set the given file filters.
		 * 
		 * @param filter the file filters
		 */
		public Filter(final String[] filter) {
			this.filter = filter;
		}

		/**
		 * Constructor to set the given file filters and a description.
		 * 
		 * @param filter the file filters
		 * @param desc the file filter description
		 */
		public Filter(final String[] filter, final String desc) {
			this.filter = filter;
			this.description = desc;
		}

		@Override
		public boolean accept(final File f) {
			if (f != null) {
				if (f.isDirectory()) {
					return true;
				}
				final String extension = getExtension(f);
				if (extension != null && this.filter != null) {
					for (final String filterEntry : this.filter) {
						if (extension.equalsIgnoreCase(filterEntry)) {
							return true;
						}
					}
				}
			}
			return false;
		}

		/**
		 * Sets the description.
		 * 
		 * @param desc
		 */
		@SuppressWarnings("unused")
		public void setDescription(final String desc) {
			this.description = desc;
		}

		@Override
		public String getDescription() {
			if (this.description != null) {
				return this.description;
			}
			return null;
		}

		/**
		 * Returns the file extension for the given file.
		 * 
		 * @param f the file
		 * @return the file extension or null
		 */
		public String getExtension(final File f) {
			final String filename = f.getName();
			final int i = filename.lastIndexOf('.');
			if (i > 0 && i < filename.length() - 1) {
				return filename.substring(i + 1).toLowerCase();
			}
			return null;
		}
	}
}